﻿//
// File:    TravModel.cs
// Project: Traveler 0.3.x (A Windows file explorer)
//
// Copyright 2011-2012 Kasey Osborn (Kasewick@gmail.com)
// Ms-PL license - Use and redistribute freely
//

using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using FileTreeSpace;
using Progress;
using TravViewed;

namespace Trav
{
    /// <summary>
    /// Define the Model super-component of the Strict MVC pattern for the Traveler project.
    /// This class provides an interface of the model to the controller.
    /// </summary>
    public sealed partial class TravModel : TravModelbase, IDisposable
    {
        public DetailModel Detail;
        public override DetailModelbase DetailView { get { return Detail; } }

        public ProgressModel Progress { get; private set; }

        private BackgroundWorker treeOpener;
        private BackgroundWorker duplFinder;

        public TravModel ()
        {
            Detail = new DetailModel (this);

            // Avoid locking the UI while opening folders so the user can move/close window.
            treeOpener = new BackgroundWorker ();
            treeOpener.DoWork += new DoWorkEventHandler (openerWork);
            treeOpener.RunWorkerCompleted += new RunWorkerCompletedEventHandler (openerComplete);

            // Avoid locking the UI while comparing files so the user can cancel the operation.
            duplFinder = new BackgroundWorker ();
            duplFinder.WorkerSupportsCancellation = true;
            duplFinder.WorkerReportsProgress = true;
            duplFinder.DoWork += new DoWorkEventHandler (finderWork);
            duplFinder.RunWorkerCompleted += new RunWorkerCompletedEventHandler (finderCompleted);
            duplFinder.ProgressChanged += new ProgressChangedEventHandler (finderProgressed);
        }

        public TravModel (string arg)
            : this ()
        {
            if (!string.IsNullOrEmpty (arg))
                Arg = arg;
        }


        public void Dispose ()
        {
            treeOpener.Dispose();
            duplFinder.Dispose();
            GC.SuppressFinalize (this);
        }


        public override bool IsBusy
        { get { return treeOpener.IsBusy || duplFinder.IsBusy; } }


        public void ShowSubfolders (bool subfoldersShown)
        {
            Detail.IsSubfoldersShown = subfoldersShown;
            OnAddressChanged ();
            ShowStatus ("");
        }


        public void OpenRootAsync (string newPath)
        {
            try
            {
                if (Tree != null)
                    CloseRoot ();

                ShowStatus ("Opening " + newPath);
                treeOpener.RunWorkerAsync (newPath);
            }
            catch (ArgumentException ex)
            {
                View.ShowMessage (ex.ToString (), "Directory Open");
                return;
            }
        }


        public void CloseRoot ()
        {
            ChangeCurrentDir ("");
            Tree = null;

            OnFolderClosed ();

            ShowStatus ("");
        }


        public void ChangeCurrentDir (string newDir)
        {
            DirPath p = null;

            if (!String.IsNullOrEmpty (newDir))
            {
                p = new DirPath (Tree, newDir);

                if (p.Count == 0)
                    throw new ArgumentException ("ChangeDir: directory not found [" + newDir + "]");
            }

            CurrentDir = newDir;

            OnAddressChanged ();

            ShowStatus ("");
        }


        public void LaunchSelections ()
        {
            if (Detail.View.SelectedCount > 1)
            {
                bool isOkay = View.ShowQuestion ("Launch " + Detail.View.SelectedCount + " files?",
                    "Confirmation Required");
                if (!isOkay)
                    return;
            }

            foreach (string fullName in Detail.View.SelectedFullNames)
                Process.Start (fullName);
        }


        public void ShowStatus (string fyi)
        {
            StatusFyi = fyi;
            RefreshStatus ();
        }

        static private string formatStatus (int count, long total, string description)
        {
            string s1 = "";

            if (count > 0)
            {
                s1 = total + " byte";
                if (total != 1)
                    s1 += 's';
                s1 += " in ";
            }

            s1 += count + " " + description;
            if (count != 1)
                s1 += 's';

            return s1;
        }


        internal void RefreshStatus ()
        {
            long selectedTotalSize = 0;
            long totalSize = 0;

            if (!String.IsNullOrEmpty (StatusFyi))
                Status = StatusFyi;
            else
            {
                for (int i = 0; i < Detail.View.Count; i++)
                {
                    long size = Detail.View.FileSize (i);

                    totalSize += size;
                    if (Detail.View.IsSelected (i))
                        selectedTotalSize +=  size;
                }

                if (Detail.View.SelectedCount != 0)
                    Status = formatStatus (Detail.View.SelectedCount, selectedTotalSize, "selected file");
                else
                    Status = formatStatus (Detail.View.Count, totalSize, "file");
            }

            OnStatusChanged ();
        }
    }
}
